﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using KZ.Exception;
using KZ.Lottery.Entities;
using KZ.Lottery.Resources;
using KZ.Utilities;

namespace KZ.Lottery.DAL
{
    public class ResultDAL
    {
        private static Result CreateResultFromReader(SqlDataReader reader)
        {
            Result result = new Result
            {
                ResultID = Utility.StringParse(reader[ResultColumns.ResultID.ToString()]),
                ResultDate = Utility.DateTimeParse(reader[ResultColumns.ResultDate.ToString()]),
                ChannelID = Utility.StringParse(reader[ResultColumns.ChannelID.ToString()]),
                ChannelName = Utility.StringParse(reader[ResultColumns.ChannelName.ToString()]),
                Head = Utility.StringParse(reader[ResultColumns.Head.ToString()]),
                Tail = Utility.StringParse(reader[ResultColumns.Tail.ToString()]),
                Status = Utility.StringParse(reader[ResultColumns.Status.ToString()])
            };

            result.StrStatus = KZ_Resource.ResourceManager.GetString(result.Status);
            result.Day = KZ_Resource.ResourceManager.GetString(result.ResultDate.DayOfWeek.ToString());

            return result;
        }

        public static Result GetResult(string resultID)
        {
            try
            {
                Result rule = new Result();

                DataAccessHelper.SqlCmd.Parameters.Add("ResultID", SqlDbType.NVarChar).Value = resultID;
                using (SqlDataReader reader = DataAccessHelper.ExecuteQuery(CommandType.StoredProcedure, KZ_StoreName.ResultGetByID))
                {
                    if (reader.Read())
                    {
                        rule = CreateResultFromReader(reader);
                    }
                }

                return rule;
            }
            catch (SqlException ex)
            {
                Log.LogEx("GetResult", ex);
                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_GET);
            }
        }

        public static List<Result> GetResultList(string channelID, DateTime from, DateTime to)
        {
            try
            {
                List<Result> resultList = new List<Result>();

                DataAccessHelper.SqlCmd.Parameters.Add("ChannelID", SqlDbType.NVarChar).Value = channelID;
                DataAccessHelper.SqlCmd.Parameters.Add("From", SqlDbType.Date).Value = from;
                DataAccessHelper.SqlCmd.Parameters.Add("To", SqlDbType.Date).Value = to;
                using (SqlDataReader reader = DataAccessHelper.ExecuteQuery(CommandType.StoredProcedure, KZ_StoreName.ResultGetList))
                {
                    while (reader.Read())
                    {
                        resultList.Add(CreateResultFromReader(reader));
                    }
                }

                return resultList;
            }
            catch (SqlException ex)
            {
                Log.LogEx("GetResultList", ex);
                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_GET);
            }
        }

        public static bool IsExistResult(DateTime resultDate, string channelID)
        {
            try
            {
                DataAccessHelper.SqlCmd.Parameters.Add("ResultDate", SqlDbType.Date).Value = resultDate;
                DataAccessHelper.SqlCmd.Parameters.Add("ChannelID", SqlDbType.NVarChar).Value = channelID;
                return Utility.IntParse(DataAccessHelper.ExecuteScalar(CommandType.StoredProcedure, KZ_StoreName.ResultIsExist)) > 0;
            }
            catch (SqlException ex)
            {
                Log.LogEx("IsExistResult", ex);
                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_ISEXIST);
            }
        }

        public static bool DeleteResult(string resultID)
        {
            try
            {
                DataAccessHelper.SqlCmd.Parameters.Add("ResultID", SqlDbType.NVarChar).Value = resultID;
                if (DataAccessHelper.ExecuteNonQuery(CommandType.StoredProcedure, KZ_StoreName.ResultDelete) > 0)
                {
                    return true;
                }

                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_DELETE);
            }
            catch (SqlException ex)
            {
                Log.LogEx("DeleteResult", ex);
                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_DELETE);
            }
        }

        public static bool ApproveResult(List<Result> resultList)
        {
            try
            {
                //// get setting value list
                List<SettingValue> settingValueList = SettingValueDAL.GetSettingValueList();
                int maxDay = settingValueList.Max(sv => sv.Day);

                List<GroupValue> groupValueList = GroupValueDAL.GetGroupValueList();
                RuleDetailGroupReportDAL ruleDetailGroupReportDAL = new RuleDetailGroupReportDAL();
                RuleDetailGroupDAL ruleDetailGroupDAL = new RuleDetailGroupDAL();
                ReportDAL reportDAL = new ReportDAL();

                string resultID = String.Empty;
                decimal revenue = 0;
                DataAccessHelper.BeginTransaction(IsolationLevel.Serializable);

                foreach (Result result in resultList)//// loop all result
                {
                    resultID += "'" + result.ResultID + "',";
                    string ruleDetailIDList = RuleDetailDAL.GetRuleDetailID(result.ResultDate.DayOfWeek.ToString(), result.ChannelID);
                    string[] ruleDetailIDArray = ruleDetailIDList.Replace("'", String.Empty).Split(',');

                    List<RuleDetailGroup> ruleDetailGroupList = RuleDetailGroupDAL.GetRuleDetailGroupList2(ruleDetailIDList);
                    foreach (string ruleDetaiID in ruleDetailIDArray)
                    {
                        Entities.Report report = new Entities.Report();
                        report.Date = result.ResultDate;
                        report.RuleDetailID = ruleDetaiID;
                        report.ChannelID = result.ChannelID;
                        report.Head = result.Head;
                        report.Tail = result.Tail;
                        report.HeadCapital = 0;
                        report.TailCapital = 0;
                        report.HeadActualCapital = 0;
                        report.TailActualCapital = 0;
                        report.HeadWinAmount = 0;
                        report.TailWinAmount = 0;

                        List<RuleDetailGroup> ruleDetailGroupTemp = new List<RuleDetailGroup>(ruleDetailGroupList.Where(rg => rg.RuleDetailID == ruleDetaiID));

                        decimal headCapital = 0;
                        decimal tailCapital = 0;
                        decimal headActualCapital = 0;
                        decimal tailActualCapital = 0;
                        decimal headTotalAmount = 0;
                        decimal tailTotalAmount = 0;
                        decimal headWinAmount = 0;
                        decimal tailWinAmount = 0;
                        decimal firstDayAmount = 0;

                        foreach (RuleDetailGroup item in ruleDetailGroupTemp)
                        {
                            report.HeadCapital += (settingValueList[item.HeadDay - 1].Value - item.FirstDayAmount) * Global.NumberOfGroup;
                            report.TailCapital += (settingValueList[item.TailDay - 1].Value - item.FirstDayAmount) * Global.NumberOfGroup;
                            report.HeadActualCapital += (settingValueList[item.HeadDay - 1].Value - item.FirstDayAmount) * Global.NumberOfGroup * Global.CapitalRate / 100;
                            report.TailActualCapital += (settingValueList[item.TailDay - 1].Value - item.FirstDayAmount) * Global.NumberOfGroup * Global.CapitalRate / 100;

                            if (item.RuleIsActived)
                            {
                                headTotalAmount += settingValueList[item.HeadDay - 1].Value;
                                tailTotalAmount += settingValueList[item.TailDay - 1].Value;

                                firstDayAmount += item.FirstDayAmount;
                            }

                            //// group win lottery
                            //// reset to first day
                            RuleDetailGroup rdg = item;
                            if (!rdg.IsGroupHead)
                            {
                                rdg = RuleDetailGroupDAL.ComputeRuleDetailGroupHeadWinOrNot(rdg, ref ruleDetailGroupTemp, ref report, ref headWinAmount, maxDay, result, groupValueList, settingValueList);
                                ruleDetailGroupDAL.UpdateRuleDetailGroupHead(rdg);
                            }
                            if (!rdg.IsGroupTail)
                            {
                                rdg = RuleDetailGroupDAL.ComputeRuleDetailGroupTailWinOrNot(rdg, ref ruleDetailGroupTemp, ref report, ref tailWinAmount, maxDay, result, groupValueList, settingValueList);
                                ruleDetailGroupDAL.UpdateRuleDetailGroupTail(rdg);
                            }
                        }

                        headCapital = (headTotalAmount - firstDayAmount) * Global.NumberOfGroup;
                        tailCapital = (tailTotalAmount - firstDayAmount) * Global.NumberOfGroup;
                        headActualCapital = headCapital * Global.CapitalRate / 100;
                        tailActualCapital = tailCapital * Global.CapitalRate / 100;
                        headWinAmount *= Global.WinRate;
                        tailWinAmount *= Global.WinRate;

                        revenue += (headWinAmount + tailWinAmount) - (headActualCapital + tailActualCapital);
                        RuleDetailDAL.UpdateRuleDetailAmount(ruleDetaiID, result.ResultDate, result.ChannelID, result.Head, result.Tail,
                            headWinAmount, tailWinAmount, headCapital, tailCapital, headActualCapital, tailActualCapital);

                        reportDAL.InsertReport(report);
                    }
                }
                resultID += "'0'";

                UpdateResultStatus(resultID);

                SettingDAL settingDAL = new SettingDAL();
                Setting setting = new Setting
                {
                    SettingID = KZ_Resource.Setting_Revenue,
                    SettingValue = revenue.ToString()
                };
                settingDAL.UpdateSetting(setting);

                DataAccessHelper.CommitTransaction();
                return true;
            }
            catch (System.Exception ex)
            {
                Log.LogEx("ApproveResult", ex);
                DataAccessHelper.RollbackTransaction();
                throw;
            }
        }

        private static bool UpdateResultStatus(string resultID)
        {
            try
            {
                DataAccessHelper.SqlCmd.Parameters.Add("ResultID", SqlDbType.NVarChar).Value = resultID;
                if (DataAccessHelper.ExecuteNonQueryWithTransaction(CommandType.StoredProcedure, KZ_StoreName.ResultUpdateStatus) > 0)
                {
                    return true;
                }

                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_UPDATE);
            }
            catch (SqlException ex)
            {
                Log.LogEx("UpdateResultStatus", ex);
                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_UPDATE);
            }
        }

        public bool InsertResult(Result result)
        {
            try
            {
                DataAccessHelper.SqlCmd.Parameters.Add("ResultID", SqlDbType.NVarChar).Value = result.ResultID;
                DataAccessHelper.SqlCmd.Parameters.Add("ResultDate", SqlDbType.Date).Value = result.ResultDate;
                DataAccessHelper.SqlCmd.Parameters.Add("ChannelID", SqlDbType.NVarChar).Value = result.ChannelID;
                DataAccessHelper.SqlCmd.Parameters.Add("Head", SqlDbType.NVarChar).Value = result.Head;
                DataAccessHelper.SqlCmd.Parameters.Add("Tail", SqlDbType.NVarChar).Value = result.Tail;
                DataAccessHelper.SqlCmd.Parameters.Add("Status", SqlDbType.NVarChar).Value = result.Status;
                if (DataAccessHelper.ExecuteNonQuery(CommandType.StoredProcedure, KZ_StoreName.ResultInsert) > 0)
                {
                    return true;
                }

                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_CHANNEL_EXIST);
            }
            catch (SqlException ex)
            {
                Log.LogEx("InsertResult", ex);
                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_INSERT);
            }
        }

        public bool UpdateResult(Result result)
        {
            try
            {
                DataAccessHelper.SqlCmd.Parameters.Add("ResultID", SqlDbType.NVarChar).Value = result.ResultID;
                DataAccessHelper.SqlCmd.Parameters.Add("ResultDate", SqlDbType.Date).Value = result.ResultDate;
                DataAccessHelper.SqlCmd.Parameters.Add("ChannelID", SqlDbType.NVarChar).Value = result.ChannelID;
                DataAccessHelper.SqlCmd.Parameters.Add("Head", SqlDbType.NVarChar).Value = result.Head;
                DataAccessHelper.SqlCmd.Parameters.Add("Tail", SqlDbType.NVarChar).Value = result.Tail;
                if (DataAccessHelper.ExecuteNonQuery(CommandType.StoredProcedure, KZ_StoreName.ResultUpdate) > 0)
                {
                    return true;
                }

                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_CHANNEL_EXIST);
            }
            catch (SqlException ex)
            {
                Log.LogEx("UpdateResult", ex);
                throw new DataAccessException(KZ_Message.BLM_ERR_RESULT_UPDATE);
            }
        }
    }
}